﻿using Microsoft.Extensions.Configuration;
using netcore_comm.Nlog;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace netcore_comm.SqlSugar
{
    public class SqlSugarFactory : ISqlSugarFactory
    {
        private INLogHelper _NLogHelper;
        private List<ConnectionStringItem> _connectionConfigs;

        public SqlSugarFactory(INLogHelper nLogHelper, IConfiguration configuration)
        {
            _NLogHelper = nLogHelper;
            _connectionConfigs = configuration.GetSection("ConnectionString").Get<List<ConnectionStringItem>>();
        }

        /// <summary>
        ///  用户确定主从库操作
        /// </summary>
        /// <param name="dataBaseName">数据库名字</param>
        /// <param name="dBOperate">读（默认），写</param>
        /// <param name="dbType">mysql（默认），sqlserver</param>
        /// <returns></returns>
        public SqlSugarClient GetInstance(string dataBaseName, DBOperateType dBOperate = DBOperateType.Read, DbType dbType = DbType.MySql)
        {
            //创建数据库对象
            SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
            {
                ConnectionString = GetConnectionString(_connectionConfigs, dataBaseName, dBOperate == DBOperateType.Write),//连接符字串
                DbType = dbType,
                IsAutoCloseConnection = true,
                ConfigId = dataBaseName,
                InitKeyType = InitKeyType.Attribute//从特性读取主键自增信息
            });

            //添加Sql打印事件，监控所有超过5秒的Sql
            db.Aop.OnLogExecuted = (sql, p) =>
            {
                //执行时间超过5秒
                if (db.Ado.SqlExecutionTime.TotalSeconds > 5)
                {
                    //代码CS文件名
                    var fileName = db.Ado.SqlStackTrace.FirstFileName;
                    //代码行数
                    var fileLine = db.Ado.SqlStackTrace.FirstLine;
                    //方法名
                    var FirstMethodName = db.Ado.SqlStackTrace.FirstMethodName;
                    //db.Ado.SqlStackTrace.MyStackTraceList[1].xxx 获取上层方法的信息
                    Console.WriteLine(sql);
                    _NLogHelper.Info($"监控所有超过5秒的Sql+[ {sql} ],位置：{fileName},{fileLine},{FirstMethodName}");

                }
            };
            return db;
        }
        public static string? GetConnectionString(List<ConnectionStringItem> configList, string dataBaseName, bool write = false)
        {
            if (dataBaseName == null || configList == null)
            {
                return null;
            }

            var item = configList.FirstOrDefault(r => dataBaseName.Equals(r.Name, StringComparison.InvariantCultureIgnoreCase));
            if (item != null)
            {
                if (write)
                {
                    return item.Write;
                }
                else if (item.Read?.Length > 0)
                {
                    if (item.Read.Length == 1)
                    {
                        return item.Read[0];
                    }

                    if (item.Read.Length == item.ReadWeight?.Length)
                    {
                        var total = item.ReadWeight.Sum();
                        if (total > 0)
                        {
                            // ReadWeight项有效，示例：
                            // Read: ["str1", "str2", "str3"]
                            // ReadWeight: [1, 0, 5]
                            // 随机区间: [0,1), null, [1,6)
                            int lowWeight = 0;
                            var selected = new Random().Next(0, total);
                            for (int i = 0; i < item.Read.Length; i++)
                            {
                                int weight = item.ReadWeight[i];
                                if (weight == 0)
                                {
                                    continue;
                                }

                                int highWeight = lowWeight + weight;
                                if (selected >= lowWeight && selected < highWeight)
                                {
                                    return item.Read[i];
                                }

                                lowWeight = highWeight;
                            }
                        }
                    }
                    else
                    {
                        return item.Read[new Random().Next(0, item.Read.Length)];
                    }
                }
            }

            return null;
        }
    }
    public class ConnectionStringItem
    {
        /// <summary>
        /// 连接字符串名字-数据库名
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 写连接字符串
        /// </summary>
        public string Write { get; set; }

        /// <summary>
        /// 读连接字符串列表
        /// </summary>
        public string[] Read { get; set; }

        /// <summary>
        /// 读连接字符串权重， 0表示暂时忽略
        /// </summary>
        public int[] ReadWeight { get; set; }
    }
}
